package Methods;

import java.util.Arrays;


import function.Function;
import function.Parser;

public class FixedPoint implements Methods{
	 // output constants
	private static final byte k = 0,   Pi = 1;
	// input constants
	private static final byte func = 0, P0 = 1,delta = 2,epsilon1=3;

	double[][] result;
	Function function;
	double point1;
	double tolerance;
    double epsilon;
	public FixedPoint(String f,double p1) throws Exception{
		this.function = Parser.toFunction(f);
		this.point1 = p1;
		this.tolerance = 0.001;
		this.epsilon=1E-8;
		
		this.result = new double[30][2];
		// Initially fill array with -1
		for (double[] a : result)
			Arrays.fill(a, -1);
		
	}
	
	public FixedPoint(String input[]) throws Exception {

		this.function = Parser.toFunction(input[func]);
		this.point1 = Double.parseDouble(input[P0]);
		this.tolerance = Double.parseDouble(input[delta]);
		this.epsilon=Double.parseDouble(input[epsilon1]);
		
		this.result = new double[30][2];
		// Initially fill array with -1
		for (double[] a : result)
			Arrays.fill(a, -1);
	}

	
	@Override
	public String[] getInputNames() {
		return new String[] { "Function", "P0" , "Tolerance","Epsilon" };
	}

	@Override
	public String[] getOutputAddresses() {

		return new String[] {"k", "Pi" };
	}

	@Override
	public String[] getSampleInput() {
		// TODO Auto-generated method stub
		return new String[] { "1*exp(-x)",".5" };
	}

	@Override
	public double[][] solve() throws Exception {
		result[0][k]=0;
		result[0][Pi]=point1;
		int i =1;
      for( i = 1 ; i < result.length;i++){
    	  result[i][k]=i;
    	  result[i][Pi]=function.evaluate(result[i-1][Pi]);
    	  double error = Math.abs(result[i][Pi]-result[i-1][Pi]);
    	  double RelError = error/(Math.abs(result[i][Pi]+epsilon));
    	  if(error<tolerance || RelError<tolerance)break;
      }
      if(i==result.length)System.out.println("Maximum Number of iterations exceeded");
		
		//trim
		i = 0;
		for(i = 0 ;i<result.length;i++)
		{
			if(result[i][0]==-1)break;
		}
		double [][] trim = Arrays.copyOf(result, i);
		return trim;
	}

	@Override
	public double getError() {
		return 0;
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
/*			FalsePosition testFalsePosition = new FalsePosition(new String[] { "x*sin(x)-1",
				"0", "2", ".01","1E-8" });*/
		
		FixedPoint testFixedPoint = new FixedPoint( "exp(-x)",.5);
		
		double[][] testResult = testFixedPoint.solve();
		
		for (double[] a : testResult)
			System.out.println(Arrays.toString(a));

	}

}